Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎉 Source Shopify: Add BalanceTransactions stream #9850

Conversation

ron-damon
Copy link
Contributor

What

Adds BalanceTransactions stream to Shopify source connector.

How

  1. Refactor incremental by id logic in a new class IncrementalByIDShopifyStream that inherits from IncrementalShopifyStream
  2. Make existing stream Collects to inherit from IncrementalByIDShopifyStream
  3. Add new stream BalanceTransactions

Recommended reading order

  1. source_shopify/source.py

🚨 User Impact 🚨

None.

Pre-merge Checklist

Expand the relevant checklist and delete the others.

New Connector

Community member or Airbyter

  • Community member? Grant edit access to maintainers (instructions)
  • Secrets in the connector's spec are annotated with airbyte_secret
  • Unit & integration tests added and passing. Community members, please provide proof of success locally e.g: screenshot or copy-paste unit, integration, and acceptance test output. To run acceptance tests for a Python connector, follow instructions in the README. For java connectors run ./gradlew :airbyte-integrations:connectors:<name>:integrationTest.
  • Code reviews completed
  • Documentation updated
    • Connector's README.md
    • Connector's bootstrap.md. See description and examples
    • docs/SUMMARY.md
    • docs/integrations/<source or destination>/<name>.md including changelog. See changelog example
    • docs/integrations/README.md
    • airbyte-integrations/builds.md
  • PR name follows PR naming conventions

Airbyter

If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.

  • Create a non-forked branch based on this PR and test the below items on it
  • Build is successful
  • Credentials added to Github CI. Instructions.
  • /test connector=connectors/<name> command is passing.
  • New Connector version released on Dockerhub by running the /publish command described here
  • After the connector is published, connector added to connector index as described here
  • Seed specs have been re-generated by building the platform and committing the changes to the seed spec files, as described here

Updating a connector

Community member or Airbyter

  • Grant edit access to maintainers (instructions)
  • Secrets in the connector's spec are annotated with airbyte_secret
  • Unit & integration tests added and passing. Community members, please provide proof of success locally e.g: screenshot or copy-paste unit, integration, and acceptance test output. To run acceptance tests for a Python connector, follow instructions in the README. For java connectors run ./gradlew :airbyte-integrations:connectors:<name>:integrationTest.
  • Code reviews completed
  • Documentation updated
    • Connector's README.md
    • Connector's bootstrap.md. See description and examples
    • Changelog updated in docs/integrations/<source or destination>/<name>.md including changelog. See changelog example
  • PR name follows PR naming conventions

Airbyter

If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.

  • Create a non-forked branch based on this PR and test the below items on it
  • Build is successful
  • Credentials added to Github CI. Instructions.
  • /test connector=connectors/<name> command is passing.
  • New Connector version released on Dockerhub by running the /publish command described here
  • After the new connector version is published, connector version bumped in the seed directory as described here
  • Seed specs have been re-generated by building the platform and committing the changes to the seed spec files, as described here

Connector Generator

  • Issue acceptance criteria met
  • PR name follows PR naming conventions
  • If adding a new generator, add it to the list of scaffold modules being tested
  • The generator test modules (all connectors with -scaffold in their name) have been updated with the latest scaffold by running ./gradlew :airbyte-integrations:connector-templates:generator:testScaffoldTemplates then checking in your changes
  • Documentation which references the generator is updated as needed.

Tests

Unit

❯ python -m pytest unit_tests
Test session starts (platform: linux, Python 3.7.9, pytest 6.2.5, pytest-sugar 0.9.4)
cachedir: .pytest_cache
rootdir: /home/da/f14/git/airbyte, configfile: pytest.ini
plugins: sugar-0.9.4, requests-mock-1.9.3, timeout-1.4.2
collecting ... 
 airbyte-integrations/connectors/source-shopify/unit_tests/test_cached_stream_state.py::test_full_refresh[Sync Started] ✓                                                                                                        5% ▌         
 airbyte-integrations/connectors/source-shopify/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync Started] ✓                                                                                                   11% █▏        
 airbyte-integrations/connectors/source-shopify/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync in progress] ✓                                                                                               16% █▋        
 airbyte-integrations/connectors/source-shopify/unit_tests/test_control_rate_limit.py::test_with_unknown_load ✓                                                                                                                 21% ██▏       
 airbyte-integrations/connectors/source-shopify/unit_tests/test_control_rate_limit.py::test_with_low_load ✓                                                                                                                     26% ██▋       
 airbyte-integrations/connectors/source-shopify/unit_tests/test_control_rate_limit.py::test_with_mid_load ✓                                                                                                                     32% ███▎      
 airbyte-integrations/connectors/source-shopify/unit_tests/test_control_rate_limit.py::test_with_high_load ✓                                                                                                                    37% ███▊      
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_correct_type[transform_object0-schema0-checks0] ✓                                                                                   42% ████▎     
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_correct_type[transform_object1-schema1-checks1] ✓                                                                                   47% ████▊     
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_correct_type[transform_object2-schema2-checks2] ✓                                                                                   53% █████▍    
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_correct_type[transform_object3-schema3-checks3] ✓                                                                                   58% █████▊    
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_string_to_number[transform_object0-schema0-checks0] ✓                                                                               63% ██████▍   
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_string_to_number[transform_object1-schema1-checks1] ✓                                                                               68% ██████▉   
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_nested_object[transform_object0-schema0-checks0] ✓                                                                                  74% ███████▍  
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_nested_array[transform_object0-schema0-checks0] ✓                                                                                   79% ███████▉  
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_nested_array[transform_object1-schema1-checks1] ✓                                                                                   84% ████████▌ 
 airbyte-integrations/connectors/source-shopify/unit_tests/test_transform.py::test_enforcer_string_to_number_in_array[transform_object0-schema0-checks0] ✓                                                                      89% ████████▉ 
 airbyte-integrations/connectors/source-shopify/unit_tests/unit_test.py::test_get_next_page_token ✓                                                                                                                             95% █████████▌
 airbyte-integrations/connectors/source-shopify/unit_tests/unit_test.py::test_privileges_validation ✓                                                                                                                          100% ██████████
============================================================================================================== warnings summary ==============================================================================================================
.venv/lib/python3.7/site-packages/airbyte_cdk/sources/streams/http/http.py:42: 1 warning
airbyte-integrations/connectors/source-shopify/unit_tests/unit_test.py: 21 warnings
  /home/da/f14/git/airbyte/airbyte-integrations/connectors/source-shopify/.venv/lib/python3.7/site-packages/airbyte_cdk/sources/streams/http/http.py:42: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    self._authenticator: HttpAuthenticator = NoAuth()

.venv/lib/python3.7/site-packages/deprecated/classic.py:173: 1 warning
airbyte-integrations/connectors/source-shopify/unit_tests/unit_test.py: 21 warnings
  /home/da/f14/git/airbyte/airbyte-integrations/connectors/source-shopify/.venv/lib/python3.7/site-packages/deprecated/classic.py:173: DeprecationWarning: Call to deprecated class HttpAuthenticator. (Use requests.auth.AuthBase instead) -- Deprecated since version 0.1.20.
    return old_new1(cls, *args, **kwargs)

-- Docs: https://docs.pytest.org/en/stable/warnings.html

Results (0.20s):
      19 passed

Integration

❯ python -m pytest integration_tests
Test session starts (platform: linux, Python 3.7.9, pytest 6.2.5, pytest-sugar 0.9.4)
cachedir: .pytest_cache
rootdir: /home/da/f14/git/airbyte, configfile: pytest.ini
plugins: sugar-0.9.4, requests-mock-1.9.3, timeout-1.4.2
collecting ... 
 airbyte-integrations/connectors/source-shopify/integration_tests/integration_test.py::test_dummy_test ✓                                                                                                                       100% ██████████

Results (0.02s):
       1 passed

Acceptance

Acceptance tests for secrets/config_oauth.json were disabled because we only have API Password.
There is 1 test failing because the account used for them doesn't have data for many streams. We've other shops that have a lot of data, but the tests take too much time to fetch all the data.

❯ python -m pytest integration_tests -p integration_tests.acceptance
Test session starts (platform: linux, Python 3.7.9, pytest 6.2.5, pytest-sugar 0.9.4)
cachedir: .pytest_cache
rootdir: /home/da/f14/git/airbyte, configfile: pytest.ini
plugins: sugar-0.9.4, requests-mock-1.9.3, timeout-1.4.2
collecting ... 
 airbyte-integrations/connectors/source-shopify/integration_tests/integration_test.py::test_dummy_test ✓                                                                                                                         6% ▋         
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_match_expected[inputs0] ✓                                                                                           11% █▎        
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_required[inputs0] ✓                                                                                                 17% █▋        
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_optional[inputs0] ✓                                                                                                 22% ██▎       
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_has_secret[inputs0] ✓                                                                                               28% ██▊       
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_secret_never_in_the_output[inputs0] ✓                                                                               33% ███▍      
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_defined_refs_exist_in_json_spec_file[inputs0] ✓                                                                     39% ███▉      
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_oauth_flow_parameters[inputs0] ✓                                                                                    44% ████▌     
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs0] ✓                                                                                              50% █████     
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs1] ✓                                                                                              56% █████▋    
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs2] ✓                                                                                              61% ██████▎   
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_discover[inputs0] ✓                                                                                            67% ██████▋   
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_defined_cursors_exist_in_schema[inputs0] ✓                                                                     72% ███████▎  
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_defined_refs_exist_in_schema[inputs0] ✓                                                                        78% ███████▊  

―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― TestBasicRead.test_read[inputs0] ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

self = <source_acceptance_test.tests.test_core.TestBasicRead object at 0x7ff703922cd0>, connector_config = SecretDict(******)
configured_catalog = ConfiguredAirbyteCatalog(streams=[ConfiguredAirbyteStream(stream=AirbyteStream(name='customers', json_schema={'type': ... 'incremental'>, cursor_field=['id'], destination_sync_mode=<DestinationSyncMode.append: 'append'>, primary_key=None)])
inputs = BasicReadTestConfig(config_path='secrets/config.json', configured_catalog_path='integration_tests/configured_catalog.j...', 'abandoned_checkouts'}, expect_records=None, validate_schema=True, validate_data_points=False, timeout_seconds=3600)
expected_records = [], docker_runner = <source_acceptance_test.utils.connector_runner.ConnectorRunner object at 0x7ff703955690>
detailed_logger = <Logger detailed_logger acceptance_tests_logs/test_core.py__TestBasicRead__test_read[inputs0].txt (DEBUG)>

    def test_read(
        self,
        connector_config,
        configured_catalog,
        inputs: BasicReadTestConfig,
        expected_records: List[AirbyteMessage],
        docker_runner: ConnectorRunner,
        detailed_logger,
    ):
        output = docker_runner.call_read(connector_config, configured_catalog)
        records = [message.record for message in filter_output(output, Type.RECORD)]
    
        assert records, "At least one record should be read using provided catalog"
    
        if inputs.validate_schema:
            self._validate_schema(records=records, configured_catalog=configured_catalog)
    
>       self._validate_empty_streams(records=records, configured_catalog=configured_catalog, allowed_empty_streams=inputs.empty_streams)

../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <source_acceptance_test.tests.test_core.TestBasicRead object at 0x7ff703922cd0>
records = [AirbyteRecordMessage(stream='collects', data={'id': 19149737197733, 'collection_id': 218563281061, 'product_id': 5630...', 'shop_url': '****', 'id': '54676127909|38210170323109'}, emitted_at=1643303891629, namespace=None), ...]
configured_catalog = ConfiguredAirbyteCatalog(streams=[ConfiguredAirbyteStream(stream=AirbyteStream(name='customers', json_schema={'type': ... 'incremental'>, cursor_field=['id'], destination_sync_mode=<DestinationSyncMode.append: 'append'>, primary_key=None)])
allowed_empty_streams = {'abandoned_checkouts', 'balance_transactions'}

    def _validate_empty_streams(self, records, configured_catalog, allowed_empty_streams):
        """
        Only certain streams allowed to be empty
        """
        counter = Counter(record.stream for record in records)
    
        all_streams = set(stream.stream.name for stream in configured_catalog.streams)
        streams_with_records = set(counter.keys())
        streams_without_records = all_streams - streams_with_records
    
        streams_without_records = streams_without_records - allowed_empty_streams
>       assert not streams_without_records, f"All streams should return some records, streams without records: {streams_without_records}"
E       AssertionError: All streams should return some records, streams without records: {'customers', 'discount_codes', 'inventory_items', 'draft_orders', 'fulfillments', 'pages', 'price_rules', 'custom_collections', 'products', 'fulfillment_orders', 'order_risks', 'order_refunds', 'metafields', 'transactions', 'orders'}
E       assert not {'custom_collections', 'customers', 'discount_codes', 'draft_orders', 'fulfillment_orders', 'fulfillments', ...}

../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:244: AssertionError

 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestBasicRead.test_read[inputs0] ⨯                                                                                                83% ████████▍ 
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_full_refresh.py::TestFullRefresh.test_sequential_reads[inputs0] ✓                                                                          89% ████████▉ 
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_incremental.py::TestIncremental.test_two_sequential_reads[inputs0] ✓                                                                       94% █████████▌
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_incremental.py::TestIncremental.test_state_with_abnormally_large_values[inputs0] ✓                                                        100% ██████████
========================================================================================================== short test summary info ===========================================================================================================
FAILED ../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestBasicRead::test_read[inputs0] - AssertionError: All streams should return some records, streams without records: {'customers', 'discount_codes', '...

Results (119.85s):
      17 passed
       1 failed

@github-actions github-actions bot added area/connectors Connector related issues area/documentation Improvements or additions to documentation labels Jan 27, 2022
@ron-damon
Copy link
Contributor Author

Hi @harshithmullapudi ! Sorry to bother you, but I just want to know if you need something else from my side to continue with the review of this PR.
Thanks in advance!

@harshithmullapudi
Copy link
Contributor

harshithmullapudi commented Feb 7, 2022 via email

@harshithmullapudi
Copy link
Contributor

Hey can you run sourceAcceptanceTests and share the screenshots?

@ron-damon
Copy link
Contributor Author

Hey can you run sourceAcceptanceTests and share the screenshots?

@harshithmullapudi , AcceptanceTests's output is present in the PR description, under Test section.
Do you want me to run them again?

@harshithmullapudi
Copy link
Contributor

Hey yeah I ran the tests and they were failing

  1. You can pull the latest image for acceptance tests docker pull airbyte/source-acceptance-test
  2. Can you run the tests again

@harshithmullapudi
Copy link
Contributor

hey looks like the way the balance stream is implemented its params are order _id. You can find more
https://github.com/airbytehq/airbyte/runs/5121246203?check_suite_focus=true for failed tests and it throws error URL path not found so can you check it?

@ron-damon
Copy link
Contributor Author

ron-damon commented Feb 14, 2022

Hy! Acceptance tests for secrets/config_oauth.json were disabled because we only have API Password.
There is 1 test failing because the account used for them doesn't have data for many streams. We've other shops that have a lot of data, but the tests take too much time to fetch all the data.

Maybe you are getting 404 because of a lack of privileges in the endpoint.

Acceptance tests

❯ docker pull airbyte/source-acceptance-test
Using default tag: latest
latest: Pulling from airbyte/source-acceptance-test
Digest: sha256:3431e847124f13a0a94a62c91de313f0e2a69c1419aa6946d0c58a8b5383dfe4
Status: Image is up to date for airbyte/source-acceptance-test:latest
docker.io/airbyte/source-acceptance-test:latest
❯ python -m pytest integration_tests -p integration_tests.acceptance
Test session starts (platform: linux, Python 3.7.9, pytest 6.2.5, pytest-sugar 0.9.4)
cachedir: .pytest_cache
rootdir: /home/da/f14/git/airbyte, configfile: pytest.ini
plugins: sugar-0.9.4, requests-mock-1.9.3, timeout-1.4.2
collecting ... 
 airbyte-integrations/connectors/source-shopify/integration_tests/integration_test.py::test_dummy_test ✓                                                                                                                         6% ▋         
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_match_expected[inputs0] ✓                                                                                           11% █▎        
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_required[inputs0] ✓                                                                                                 17% █▋        
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_optional[inputs0] ✓                                                                                                 22% ██▎       
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_has_secret[inputs0] ✓                                                                                               28% ██▊       
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_secret_never_in_the_output[inputs0] ✓                                                                               33% ███▍      
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_defined_refs_exist_in_json_spec_file[inputs0] ✓                                                                     39% ███▉      
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestSpec.test_oauth_flow_parameters[inputs0] ✓                                                                                    44% ████▌     
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs0] ✓                                                                                              50% █████     
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs1] ✓                                                                                              56% █████▋    
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestConnection.test_check[inputs2] ✓                                                                                              61% ██████▎   
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_discover[inputs0] ✓                                                                                            67% ██████▋   
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_defined_cursors_exist_in_schema[inputs0] ✓                                                                     72% ███████▎  
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestDiscovery.test_defined_refs_exist_in_schema[inputs0] ✓                                                                        78% ███████▊  

―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― TestBasicRead.test_read[inputs0] ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

self = <source_acceptance_test.tests.test_core.TestBasicRead object at 0x7f1ca70bcc10>, connector_config = SecretDict(******)
configured_catalog = ConfiguredAirbyteCatalog(streams=[ConfiguredAirbyteStream(stream=AirbyteStream(name='customers', json_schema={'type': ... 'incremental'>, cursor_field=['id'], destination_sync_mode=<DestinationSyncMode.append: 'append'>, primary_key=None)])
inputs = BasicReadTestConfig(config_path='secrets/config.json', configured_catalog_path='integration_tests/configured_catalog.j...s={'abandoned_checkouts'}, expect_records=None, validate_schema=True, validate_data_points=False, timeout_seconds=3600)
expected_records = [], docker_runner = <source_acceptance_test.utils.connector_runner.ConnectorRunner object at 0x7f1ca6f75e50>
detailed_logger = <Logger detailed_logger acceptance_tests_logs/test_core.py__TestBasicRead__test_read[inputs0].txt (DEBUG)>

    def test_read(
        self,
        connector_config,
        configured_catalog,
        inputs: BasicReadTestConfig,
        expected_records: List[AirbyteMessage],
        docker_runner: ConnectorRunner,
        detailed_logger,
    ):
        output = docker_runner.call_read(connector_config, configured_catalog)
        records = [message.record for message in filter_output(output, Type.RECORD)]
    
        assert records, "At least one record should be read using provided catalog"
    
        if inputs.validate_schema:
            self._validate_schema(records=records, configured_catalog=configured_catalog)
    
>       self._validate_empty_streams(records=records, configured_catalog=configured_catalog, allowed_empty_streams=inputs.empty_streams)

../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <source_acceptance_test.tests.test_core.TestBasicRead object at 0x7f1ca70bcc10>
records = [AirbyteRecordMessage(stream='collects', data={'id': 19149737197733, 'collection_id': 218563281061, 'product_id': 5630...', 'shop_url': '****', 'id': '54676127909|38210170323109'}, emitted_at=1644870000607, namespace=None), ...]
configured_catalog = ConfiguredAirbyteCatalog(streams=[ConfiguredAirbyteStream(stream=AirbyteStream(name='customers', json_schema={'type': ... 'incremental'>, cursor_field=['id'], destination_sync_mode=<DestinationSyncMode.append: 'append'>, primary_key=None)])
allowed_empty_streams = {'abandoned_checkouts'}

    def _validate_empty_streams(self, records, configured_catalog, allowed_empty_streams):
        """
        Only certain streams allowed to be empty
        """
        counter = Counter(record.stream for record in records)
    
        all_streams = set(stream.stream.name for stream in configured_catalog.streams)
        streams_with_records = set(counter.keys())
        streams_without_records = all_streams - streams_with_records
    
        streams_without_records = streams_without_records - allowed_empty_streams
>       assert not streams_without_records, f"All streams should return some records, streams without records: {streams_without_records}"
E       AssertionError: All streams should return some records, streams without records: {'order_risks', 'price_rules', 'order_refunds', 'products', 'customers', 'balance_transactions', 'metafields', 'fulfillments', 'pages', 'transactions', 'discount_codes', 'orders', 'draft_orders', 'fulfillment_orders', 'inventory_items', 'custom_collections'}
E       assert not {'balance_transactions', 'custom_collections', 'customers', 'discount_codes', 'draft_orders', 'fulfillment_orders', ...}

../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:244: AssertionError

 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestBasicRead.test_read[inputs0] ⨯                                                                                                83% ████████▍ 
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_full_refresh.py::TestFullRefresh.test_sequential_reads[inputs0] ✓                                                                          89% ████████▉ 
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_incremental.py::TestIncremental.test_two_sequential_reads[inputs0] ✓                                                                       94% █████████▌
 airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_incremental.py::TestIncremental.test_state_with_abnormally_large_values[inputs0] ✓                                                        100% ██████████
========================================================================================================== short test summary info ===========================================================================================================
FAILED ../../bases/source-acceptance-test/source_acceptance_test/tests/test_core.py::TestBasicRead::test_read[inputs0] - AssertionError: All streams should return some records, streams without records: {'order_risks', 'price_rules', 'o...

Results (142.10s):
      17 passed
       1 failed
         - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:310 TestBasicRead.test_read[inputs0]

@marcosmarxm
Copy link
Member

@ron-damon we're waiting our team add data to validate the final part of integration tests.

Copy link
Collaborator

@bazarnov bazarnov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine, but this implementation is not complete.
It misses the Payouts stream, which is needed in order to fetch the BalanceTransactions stream, see the docs: https://shopify.dev/api/admin-rest/2022-01/resources/transactions#resource-description
We need to implement the Payouts stream to have the payout_id and use it inside the BalaceTransactions stream API calls.

What can be done here at this point:

  1. The contributor just adds the Payouts stream and makes it work with BalanceTransactions stream using stream_slices method.
  2. We will leverage this contribution in order to complete it by ourselves, refactor this implementation and finish it by covering all the implementation and all the tests on our end.

@ron-damon @harshithmullapudi WDYT?

@ron-damon
Copy link
Contributor Author

Hey @bazarnov, thanks for taking a look.

According to the documentation, the payout_id is optional, maybe it's confusing because the examples are based on the payout_id. Even more, there're some transactions that have payout_id=null.

IMHO, it's better to have this stream independent from another stream (Payouts in this case), and simply use id as cursor key + since_id as a parameter.

Make sense to you?

@bazarnov
Copy link
Collaborator

bazarnov commented Mar 21, 2022

Hey @bazarnov, thanks for taking a look.

According to the documentation, the payout_id is optional, maybe it's confusing because the examples are based on the payout_id. Even more, there're some transactions that have payout_id=null.

IMHO, it's better to have this stream independent from another stream (Payouts in this case), and simply use id as cursor key + since_id as a parameter.

Make sense to you?

Got your point. It's reasonable having the BalanceTransactions as independent stream.
Could you please merge with master and fix the current branch conflicts? There were changes applied recently, please reuse the Collects stream as an example to implement BalanceTransactions after you merge with master. There is no need to create another base class to inherit from it.

After that, please edit the basic_read: block, empty_streams: property, inside of acceptance-test-config.yml with something like this, to have the SAT tests completed:

empty_streams: ["abandoned_checkouts", "balance_transactions"]

This means "balance_transactions" could return no records during the sync.

If you faced with the issue of missing config_oauth.json during SAT tests, please add one more file into the secrets folder, with this context:

{
    "shop": {YOUR_SHOP},
    "start_date": {THE DATE FROM CONFIG.JSON},
    "credentials": {
      "auth_method": "oauth2.0",
      "client_id": "",
      "client_secret": "",
      "access_token": {YOUR TOKEN FROM CONFIG.JSON}
    }
}

This will make it pass.

If you have any questions, feel free to ask here.

@ron-damon
Copy link
Contributor Author

I think we will continue this in #10204

@bazarnov
Copy link
Collaborator

bazarnov commented Mar 22, 2022

I think we can close this PR, due to this one

@bazarnov bazarnov closed this Mar 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/connectors Connector related issues area/documentation Improvements or additions to documentation community on-hold
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants